// ----------------------------------------------------------------------------
// diabindEnumDebugStreams.h
// DIA Enumerate debug streams
// ----------------------------------------------------------------------------

#pragma once

// ----------------------------------------------------------------------------

#include "diabindEnumDebugStreamData.h"

// ----------------------------------------------------------------------------

namespace diabind
{

// ----------------------------------------------------------------------------

interface IEnumDebugStreams
{
    virtual ~IEnumDebugStreams() {}

    virtual LONG get_Count() = 0;
    virtual CEnumDebugStreamDataPtr Item(DWORD index) = 0;
};
typedef boost::shared_ptr< IEnumDebugStreams > CEnumDebugStreamsPtr;

// ----------------------------------------------------------------------------

template< class DiaEnumDebugStreamsT >
class CEnumDebugStreamsImpl : public IEnumDebugStreams
{
    typedef _com_IIID< DiaEnumDebugStreamsT, &__uuidof(DiaEnumDebugStreamsT) > CIiid;
    typedef _com_ptr_t< CIiid > CImplPtr;
public:
    explicit CEnumDebugStreamsImpl(const CImplPtr &pEnumDebugStreams)
        : m_pEnumDebugStreams(pEnumDebugStreams)
    {
        HRESULT hResult = m_pEnumDebugStreams->get_Count(&m_nCount);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumDebugStreams::get_Count");
    }

    virtual LONG get_Count() override
    {
        return m_nCount;
    }

    virtual CEnumDebugStreamDataPtr Item(DWORD index) override
    {
        if (index >= static_cast<DWORD>(m_nCount))
            throw CPyException(PyExc_IndexError, "index out of range");

        return ItemT(&DiaEnumDebugStreamsT::Item, "IDiaEnumDebugStreams::Item", index);
    }

protected:
    template< class DiaEnumDebugStreamDataT >
    CEnumDebugStreamDataPtr ItemT(
        HRESULT (STDMETHODCALLTYPE DiaEnumDebugStreamsT::*pMethod)(VARIANT, DiaEnumDebugStreamDataT **),
        const char *szMethodName,
        long index
    )
    {
        _com_ptr_t< _com_IIID<DiaEnumDebugStreamDataT, &__uuidof(DiaEnumDebugStreamDataT)> > pEnumDebugStreamData;
        HRESULT hResult = (m_pEnumDebugStreams->*pMethod)(_variant_t(index, VT_I4), &pEnumDebugStreamData);
        if (S_OK != hResult)
            throw CException(hResult, szMethodName);

        return CEnumDebugStreamDataPtr( new CEnumDebugStreamDataImpl<DiaEnumDebugStreamDataT>(pEnumDebugStreamData) );
    }

private:
    CImplPtr m_pEnumDebugStreams;
    LONG m_nCount;
};

// ----------------------------------------------------------------------------

}   // namespace diabind

// ----------------------------------------------------------------------------
